home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / comm / bbs / cit_src_AD08.lha / modem.c < prev    next >
C/C++ Source or Header  |  1997-12-15  |  44KB  |  1,896 lines

  1. /*
  2. *       modem.c
  3. *
  4. * modem code for Citadel bulletin board system
  5. * NB: this code is rather machine-dependent:  it will typically
  6. * need some twiddling for each new installation.
  7. *       82Nov05 CrT
  8. *
  9. * now this file is mostly for upper layer modem handling and the protocols,
  10. * so it may need no fiddling.
  11. *       88May07 HAW
  12. */
  13. /*
  14. *       history
  15. *
  16. * 85Nov09 HAW  Warning bell before timeout.
  17. * 85Oct27 HAW  Cermetek support eliminated.
  18. * 85Oct18 HAW  2400 support.
  19. * 85Sep15 HAW  Put limit in ringSysop().
  20. * 85Aug17 HAW  Update for gotCarrier().
  21. * 85Jul05 HAW  Insert fix code (Brian Riley) for 1200 network.
  22. * 85Jun11 HAW  Fix readFile to recognize loss of carrier.
  23. * 85May27 HAW  Code for networking time out.
  24. * 85May06 HAW  Code for daily timeout.
  25. * 85Mar07 HAW  Stick in Sperry PC mods for MSDOS.
  26. * 85Feb22 HAW  Upload/download implemented.
  27. * 85Feb20 HAW  IMPERVIOUS flag implemented.
  28. * 85Feb17 HAW  Baud change functions installed.
  29. * 85Feb09 HAW and Sr.  Chat bug analyzed by Sr.
  30. * 85Jan16 JLS  fastIn modified for CR being first character from modem.
  31. * 85Jan04 HAW  Code added but not tested for new WC functions.
  32. * 84Sep12 HAW  Continue massacre of portability -- bye, pMIReady.
  33. * 84Aug30 HAW  Wheeee!!  MS-DOS time!!
  34. * 84Aug22 HAW  Compilation directive for 8085 chips inserted.
  35. * 84Jul08 JLS & HAW ReadFile() fixed for the 255 rollover.
  36. * 84Jul03 JLS & HAW All references to putCh changed to putChar.
  37. * 84Jun23 HAW & JLS Local unused variables zapped.
  38. * 84Mar07 HAW  Upgrade to BDS 1.50a begun.
  39. * 83Mar01 CrT  FastIn() ignores LFs etc -- CRLF folks won't be trapped.
  40. * 83Feb25 CrT  Possible fix for backspace-in-message-entry problem.
  41. * 83Feb18 CrT  fastIn() upload mode cutting in on people.  Fixed.
  42. * 82Dec16 dvm  modemInit revised for FDC-1, with kludge for use with
  43. *   Big Board development system
  44. * 82Dec06 CrT  2.00 release.
  45. * 82Nov15 CrT  readfile() & sendfile() borrowed from TelEdit.c
  46. * 82Nov05 CrT  Individual history file established
  47. */
  48. #include "ctdl.h"
  49. void DumpToFile(int LastReceived, int BufSize, CRC_TYPE tc, CRC_TYPE oc);
  50. /*
  51. *       Contents
  52. *
  53. * BBSCharReady()    returns true if user input is ready
  54. * ClearWX()   finishes a WXMODEM transmission
  55. * CommonPacket()    reads a block
  56. * CommonWrite()   writes a block to wherever
  57. * FlowControl()   flow control handler for WXMODEM
  58. * GenTrInit()   general init for individual protocols
  59. * getMod()    bottom-level modem-input filter
  60. * iChar()     top-level user-input function
  61. * initTransfers()   initial data buffers of protocols
  62. * interact()    chat mode
  63. * JumpStart()   gets protocol reception going
  64. * MIReady()   check MS-DOS interrupt for data
  65. * modIn()     returns a user char
  66. * modemInit()   top-level initialize-all-modem-stuff
  67. * oChar()     top-level user-output function
  68. * Reception()   receive data via protocol
  69. * recWX()     receive data via WXMODEM
  70. * recWXchar()   receive a WXMODEM char, stripped of DLE
  71. * recXYmodem()    receive data via X or Y MODEM
  72. * ringSysop()   signal chat-mode request
  73. * SendCmnBlk()    sends a WX/X/Y/MODEM block
  74. * sendWCChar()    send file with WC-protocol handshaking
  75. * sendWXchar()    send a char for WXMODEM
  76. * sendWXModem()   send data with WXMODEM protocol
  77. * sendYMChar()    send file with YMODEM protocol
  78. * SummonSysop()   rings bell for ^T
  79. * SurreptitiousChar() process a console character in MODEM
  80. * Transmission()    handles protocol transmission
  81. * WXResponses()   handles NAK/ACK XON/XOFF for WXMODEM
  82. * XYBlock()   common routine for X & Y modem
  83. * XYClear()   finished X or Y MODEM transmission
  84. * YMHdr()     YMODEM BATCH header handler
  85. */
  86. void ReActivate_Window(void);  /* allow window to be activated */
  87. char justLostCarrier = FALSE;   /* Modem <==> rooms connection  */
  88. char newCarrier = FALSE;   /* Just got carrier  */
  89. char onConsole;     /* Who's in control?!?  */
  90. int  outPut = NORMAL;
  91. char modStat;     /* Whether modem had carrier LAST time  */
  92. /* you checked. */
  93. char CallSysop = FALSE;   /* Call sysop on user logout  */
  94. char whichIO = CONSOLE;   /* CONSOLE or MODEM */
  95. #ifdef NEED_VISIBLE
  96. char visibleMode;   /* make non-printables visible? */
  97. #endif
  98. static char captureOn = FALSE;
  99. static FILE *cptFile;
  100. char haveCarrier;   /* set if DCD == TRUE */
  101. char textDownload = FALSE;  /* read host files, TRUE => ASCII */
  102. char echo;      /* Either NEITHER, CALLER, or BOTH  */
  103. char echoChar;      /* What to echo with if echo == NEITHER */
  104. int  TransProtocol;   /* Transfer protocol value  */
  105. int  upDay;     /* Day system was brought up  */
  106. char nextDay;     /* Come down tomorrow rather than today?*/
  107. int  timeCrash;
  108. char anyEcho = TRUE;
  109. char warned;
  110. long netBytes;
  111. char ChatMode;
  112. char NoConsoleBanner;   /* defaults to FALSE */
  113. long TempBytes;
  114. char ConOnly = FALSE;
  115. static char PB = 0;
  116. /* Block transfer variables */
  117. TransferBlock Twindow[4];
  118. #define blk Twindow[0]
  119. int  CurWindow,   /* For sequence #, init to 1 */
  120. TrBlock,    /* For block #, init to 1 */
  121. StartWindow,  /* First block of current Twindow, init = 1 */
  122. TrCount,    /* Byte accumulator counter, init to 0 */
  123. LastSent,   /* Last seq block sent to receiver, regardless of ACK */
  124. CurYBufSize,  /* Size of current YMODEM block to send */
  125. GlobalHeader; /* Starting char of transfer (YMODEM) */
  126. char DoCRC,   /* True if doing CRC */
  127. DLinkError, /* For conveying errors during WXMODEM */
  128. TrError,    /* True only on fatal error */
  129. DLEsignal;    /* True only when an WXMODEM read involved a DLE */
  130. AN_UNSIGNED *DataBuf;
  131. int      TrCksm;  /* Checksum variable for transmissions */
  132. static char *msg[] =
  133.   {
  134.   "NO ERROR",
  135.   "BAD DLE",
  136.   "EARLY SYN",
  137.   "DATA TIMEOUT",
  138.   "BAD CRC",
  139.   "BAD CHECKSUM",
  140.   "BAD SECTOR COMPLEMENT",
  141.   "SYNCH ERROR",
  142.   "WRITE ERROR",
  143.   "CARRIER LOSS"
  144.  
  145.   };
  146. #define WindowFull()    IsSent(0) && IsSent(1) && IsSent(2) && IsSent(3)
  147. #define WindowEmpty()   IsDone(0) && IsDone(1) && IsDone(2) && IsDone(3)
  148. #define IsDone(x) (IsAcked(x) || NotUsed(x))
  149. #define IsSent(x) (Twindow[x].status == SENT)
  150. #define IsAcked(x)  (Twindow[x].status == ACKED)
  151. #define NotUsed(x)  (Twindow[x].status == NOT_USED)
  152. /*
  153. * This table presupposes that XMODEM is defined as 1, YMODEM as 2, WXMODEM
  154. * as 3.  Used only by CommonPacket().
  155. */
  156. static int time_table[] =
  157.   {
  158.   0, 1, 4, 15
  159.  
  160.   };
  161. long ByteCount;
  162. extern MessageBuffer   msgBuf;  /* Message buffer */
  163. extern CONFIG    cfg;   /* Configuration variables  */
  164. extern logBuffer logBuf;  /* Log buffer of a person */
  165. extern aRoom  roomBuf;  /* Room buffer  */
  166. extern FILE *upfd;
  167. extern char loggedIn; /* Is we logged in? */
  168. extern char prevChar; /* previous char  */
  169. extern char outFlag;  /* output flag  */
  170. extern char ExitToMsdos;  /* Kill program flag  */
  171. extern int  exitValue;
  172. /* net stuff vars should go here */
  173. extern char inNet;
  174. extern FILE *netLog;
  175. extern FILE *strollfd;
  176. /* bloooooop! */
  177. extern char netDebug;
  178. extern PROTO_TABLE  Table[];
  179. /*
  180. * BBSCharReady()
  181. *
  182. * This returns TRUE if char is available from user.
  183. * NB: user may be on modem, or may be sysop in CONSOLE mode.
  184. */
  185. char BBSCharReady()
  186.   {
  187.   return (char) (PB || ((haveCarrier && whichIO == MODEM) && MIReady()) ||
  188.   (whichIO == CONSOLE  &&   KBReady()));
  189.  
  190.   }
  191. #ifdef WXMODEM_AVAILABLE
  192. /*
  193. * ClearWX()
  194. *
  195. * This finishes a WXMODEM transmission.
  196. */
  197. int ClearWX()
  198.   {
  199.   int rover, BlockRover, TempSent, SendEOT;
  200.   if (!gotCarrier())
  201.   return CARR_LOSS;
  202.   outMod(EOT);  /* Forces us to wait until output buffer is flushed */
  203.   while (!WindowEmpty())
  204.     {
  205.     WXResponses();
  206.     for (BlockRover = (LastSent + 1) % 4, TempSent = LastSent, SendEOT=0;
  207.     BlockRover != LastSent; BlockRover = (BlockRover + 1) % 4)
  208.       {
  209.       if (Twindow[BlockRover].status != SECTOR_READY) break;
  210.       SendEOT++;
  211.       SendCmnBlk(WXMDM, Twindow + BlockRover, sendWXchar, SECTSIZE);
  212.       Twindow[BlockRover].status = SENT;
  213.       TempSent = BlockRover;
  214.  
  215.       }
  216.     LastSent = TempSent;
  217.     if (!gotCarrier())
  218.     return CARR_LOSS;
  219.     if (SendEOT) outMod(EOT);
  220.  
  221.     }
  222.   for (rover = 1; rover < MAX_WX_ERRORS; rover++)
  223.     {
  224.     if (!gotCarrier())
  225.     return CARR_LOSS;
  226.     if (receive(3) != ACK) outMod(EOT);
  227.     else return TRAN_SUCCESS;
  228.  
  229.     }
  230.   return TRAN_FAILURE;
  231.  
  232.   }
  233. #endif
  234. /*
  235. * CommonPacket()
  236. *
  237. * This reads a block of data (XMDM, YMDM, WXMDM).
  238. */
  239. int CommonPacket(char type, int size, int (*recFn)(int t), int *Sector)
  240.   {
  241.   int  comp, cksm, i, c, hi, lo, time;
  242.   CRC_TYPE crc;
  243.   #ifdef NEED_NET_DEBUG_ERRORS
  244.   CRC_TYPE oc;
  245.   #endif
  246.   /*
  247.   * Format:
  248.   *
  249.   * <SOH | STX><Sec#><w Sec#><size bytes of data><checksum or CRC>
  250.   *
  251.   * SOH | STX has already been received by the caller.  type is used for
  252.   * protocol specific problems, as follows.
  253.   *
  254.   * WXMDM:
  255.   * 1. When SYN is detected without DLEsignal == TRUE, this indicates a bad
  256.   *    packet problem, so that must be checked.
  257.   */
  258.   time = time_table[type];
  259.   *Sector = (*recFn)(time);   /* Get Sector # */
  260.   #ifdef WXMODEM_AVAILABLE
  261.   if (type == WXMDM && *Sector == SYN && !DLEsignal) return EARLY_SYN;
  262.   #endif
  263.   comp = (*recFn)(time);  /* Get Sector #'s complement */
  264.   #ifdef WXMODEM_AVAILABLE
  265.   if (type == WXMDM && comp == SYN && !DLEsignal) return EARLY_SYN;
  266.   #endif
  267.   for (i = cksm = 0; i < size; i++)
  268.     {
  269.     /* Get data block */
  270.     if ((c = (*recFn)(time)) == ERROR)
  271.       {
  272.       if (!gotCarrier())
  273.       return CARR_LOSS;
  274.       if (cfg.BoolFlags.debug)splitF(netLog, "TIMEOUT on byte %d\n", i);
  275.       return DATA_TIMEOUT;
  276.  
  277.       }
  278.     #ifdef WXMODEM_AVAILABLE
  279.     if (  type == WXMDM &&
  280.     c == SYN && !DLEsignal  )
  281.       {
  282.       return EARLY_SYN;
  283.  
  284.       }
  285.     #endif
  286.     DataBuf[i] = c;
  287.     cksm = (c + cksm) & 0xFF;
  288.     if (!gotCarrier()) return CARR_LOSS;
  289.  
  290.     }
  291.   hi = (*recFn)(time);  /* Get cksm or hi byte of CRC */
  292.   if (DoCRC)
  293.     {
  294.     lo = (*recFn)(time);    /* Get lo byte of CRC */
  295.     crc = (hi << 8) + lo;
  296.     if (*Sector + comp == 0xff) /* Validations... */
  297.     if (crc != calcrc(DataBuf, size))
  298.       {
  299.       #ifdef NEED_NET_DEBUG_ERRORS
  300.       splitF(netLog, "CRC error: we calc %x, they sent %x\n", oc=calcrc(DataBuf, size), crc);
  301.       DumpToFile(*Sector, size, crc, oc);
  302.       #endif
  303.       return BAD_CRC;
  304.  
  305.       }
  306.  
  307.     }
  308.   else
  309.     {
  310.     if (hi != cksm)
  311.     return BAD_CKSM;
  312.  
  313.     }
  314.   if (*Sector + comp != 0xFF)
  315.     {
  316.     /* Check this to make sure, too */
  317.     #ifdef NEED_NET_DEBUG_ERRORS
  318.     if (inNet != NON_NET && netDebug)
  319.     splitF(netLog, "BT: %x %x\n", *Sector, comp);
  320.     printf("\nBT: %x %x\n", *Sector, comp);
  321.     #endif
  322.     return BAD_SEC_COMP;
  323.  
  324.     }
  325.   return NO_ERROR;
  326.  
  327.   }
  328. /*
  329. * CommonWrite()
  330. *
  331. * This function writes a block of data to wherever.
  332. */
  333. int CommonWrite(int (*WriteFn)(int c), int size)
  334.   {
  335.   int i;
  336.   for (i = 0; i < size; i++)
  337.   if ((*WriteFn)(DataBuf[i]) == ERROR)
  338.   return WRITE_ERROR;
  339.   return NO_ERROR;
  340.  
  341.   }
  342. #ifdef WXMODEM_AVAILABLE
  343. /*
  344. * FlowControl()
  345. *
  346. * This function handles XON/XOFF for WXMODEM.
  347. */
  348. void FlowControl()
  349.   {
  350.   int val;
  351.   startTimer(WORK_TIMER);
  352.   do
  353.   val = receive(1); /* Use receive in this instance */
  354.   while (val != XON && chkTimeSince(WORK_TIMER) < 10);
  355.  
  356.   }
  357. #endif
  358. /*
  359. * GenTrInit()
  360. *
  361. * General protocol initializations.
  362. */
  363. void GenTrInit()
  364.   {
  365.   int i;
  366.   for (i = 0; i < 4; i++) Twindow[i].status = NOT_USED;
  367.   CurWindow  = TrBlock   = StartWindow = 1;
  368.   TrCount    = LastSent  = TrCksm = 0;
  369.   DLinkError = DLEsignal = FALSE;
  370.   TrError    = TRAN_SUCCESS;
  371.   DoCRC = TRUE;
  372.  
  373.   }
  374. /*
  375. * iChar()
  376. *
  377. * This is the top-level user-input function -- this is the function the rest
  378. * of Citadel uses to obtain user input.
  379. */
  380. char iChar()
  381.   {
  382.   char  c;
  383.   extern AN_UNSIGNED crtColumn; /* current position on screen */
  384.   if (justLostCarrier)   return 0;    /* ugly patch   */
  385.   c = cfg.filter[modIn() & 0x7f];
  386.   switch (echo)
  387.     {
  388.     case BOTH:
  389.     if (haveCarrier)
  390.       {
  391.       if (c == '\n')
  392.         {
  393.         if (!HalfDup) doCR();
  394.  
  395.         }
  396.       else
  397.       if (!HalfDup) outMod(c);
  398.  
  399.       }
  400.     mputChar(c);  /* Let putChar decide if it should go on console */
  401.     crtColumn += (c == '\b') ? -1 : 1;
  402.     break;
  403.     case CALLER:
  404.     if (whichIO == MODEM)
  405.       {
  406.       if (c == '\n')
  407.         {
  408.         if (!HalfDup) doCR();
  409.  
  410.         }
  411.       else
  412.         {
  413.         if (!HalfDup) outMod(c);
  414.  
  415.         }
  416.  
  417.       }
  418.     else
  419.       {
  420.       mputChar(c);
  421.  
  422.       }
  423.     crtColumn += (c == '\b') ? -1 : 1;
  424.     break;
  425.     case NEITHER:
  426.     if (echoChar != '\0')
  427.       {
  428.       if (whichIO == MODEM)
  429.         {
  430.         if (c == '\n') doCR();
  431.         else if (c <= ' ') outMod(c);
  432.         else  outMod(echoChar);
  433.  
  434.         }
  435.       else
  436.         {
  437.         if (c == '\n') doCR();
  438.         else if (c <= ' ') mputChar(c);
  439.         else  mputChar(echoChar);
  440.  
  441.         }
  442.       crtColumn += (c == '\b') ? -1 : 1;
  443.  
  444.       }
  445.     break;
  446.  
  447.     }
  448.   return(c);
  449.  
  450.   }
  451. /*
  452. * initTransfers()
  453. *
  454. * This initializes data buffers for protocol transfers.
  455. */
  456. void initTransfers()
  457.   {
  458.   int i;
  459.   for (i = 1; i < 4; i++)
  460.     {
  461.     Twindow[i].buf = GetDynamic(SECTSIZE);
  462.  
  463.     }
  464.   DataBuf = blk.buf = GetDynamic(YM_BLOCK_SIZE);
  465.  
  466.   }
  467. /*
  468. * interact()
  469. *
  470. * Here we try to chat with the users.  Or at least the modem.
  471. */
  472. void interact(char ask)
  473.   {
  474.   char CallerDumb;
  475.   char last = 0;
  476.   int  c = 0;
  477.   extern char *APPEND_TEXT;
  478.   ChatMode = TRUE;
  479.   printf("\nDirect modem-interaction mode\n");
  480.   if (ask)
  481.     {
  482.     ConOnly = TRUE;
  483.     CallerDumb = getYesNo("DUMBCL");
  484.     ConOnly = FALSE;
  485.     if (!gotCarrier()) EnableModem(FALSE);
  486.  
  487.     }
  488.   else
  489.     {
  490.     CallerDumb = FALSE;
  491.  
  492.     }
  493.   printf("<ESC> to exit\n");
  494.   /* incredibly ugly code.  Rethink sometime: */
  495.   while (c != SPECIAL )
  496.     {
  497.     c = 0;
  498.     BufferingOn();
  499.     if (MIReady())
  500.       {
  501.       c = inp() & 0x7f;
  502.       if( c == '\0')c = SPECIAL;
  503.       if (c == SPECIAL && !ask) c = 0;
  504.       if (c != '\r') c = cfg.filter[c];
  505.       if (c != '\r')
  506.         {
  507.         if (CallerDumb && c != ESC && c != 0)   outMod(c);
  508.         if (c != 0) interOut(c);
  509.  
  510.         }
  511.       else
  512.         {
  513.         interOut('\n');
  514.         if (CallerDumb)
  515.           {
  516.           outMod('\r');
  517.           outMod('\n');
  518.  
  519.           }
  520.  
  521.         }
  522.  
  523.       }
  524.     else if (KBReady())
  525.       {
  526.       BufferingOff();
  527.       if ((c = getCh()) == '\r') c = '\n';
  528.       if (c == CPT_SIGNAL)
  529.         {
  530.         /* capture input? */
  531.         captureOn = !captureOn;
  532.         if (captureOn)
  533.           {
  534.           if ((cptFile = safeopen("chat.txt", APPEND_TEXT)) == NULL)
  535.             {
  536.             printf("\nCOULDN'T OPEN/APPEND TO CHAT.TXT!\n");
  537.             captureOn = FALSE;
  538.  
  539.             }
  540.           else
  541.             {
  542.             printf("\nAppending to CHAT.TXT\n");
  543.             mPrintf(
  544.             "\n WARNING from Citadel: This chat is now being recorded.\n ");
  545.  
  546.             }
  547.  
  548.           }
  549.         else
  550.           {
  551.           fclose(cptFile);
  552.           printf("\nCapture finished\n");
  553.           mPrintf(
  554.           " \nMessage from Citadel: Chat no longer being captured.\n ");
  555.  
  556.           }
  557.  
  558.         }
  559.       else if (c == 5 || ChatEat(c))
  560.         {
  561.         ChatGrab(TRUE);
  562.  
  563.         }
  564.       else if (c == 6 || ChatSend(c))
  565.         {
  566.         ChatGrab(FALSE);
  567.  
  568.         }
  569.       else if (c != NEWLINE)
  570.         {
  571.         if (CallerDumb)  interOut(c);
  572.         if (c != ESC && c != '\\')   outMod(c);
  573.         else
  574.           {
  575.           if (last == '\\')
  576.             {
  577.             outMod(c);
  578.             c = 0;
  579.  
  580.             }
  581.  
  582.           }
  583.         last = c;
  584.  
  585.         }
  586.       else
  587.         {
  588.         outMod('\r');
  589.         if (CallerDumb)
  590.           {
  591.           interOut('\n');
  592.           outMod('\n');
  593.  
  594.           }
  595.  
  596.         }
  597.  
  598.       }
  599.     else
  600.       {
  601.       BufferingOff();
  602.       BeNice(CHAT_NICE);
  603.       DoTimeouts();
  604.  
  605.       }
  606.  
  607.     }
  608.   if (captureOn)
  609.     {
  610.     captureOn = FALSE;
  611.     fclose(cptFile);
  612.  
  613.     }
  614.   if (!gotCarrier() && whichIO == CONSOLE)
  615.   DisableModem(FALSE);
  616.   ChatMode = FALSE;
  617.   BufferingOff();
  618.  
  619.   }
  620. /*
  621. * ChatGrab()
  622. *
  623. * This function implements downloading from Chat.
  624. */
  625. void ChatGrab(char Up)
  626.   {
  627.   SListBase CSelects =
  628.     {
  629.     NULL, FindSelect, NULL, NoFree, NULL
  630.  
  631.     };
  632.   char *Protocols[] =
  633.     {
  634.     TERM "Xmodem",
  635.     #ifdef WXMODEM_AVAILABLE
  636.     TERM "Wxmodem",
  637.     #endif
  638.     TERM "Ymodem",
  639.     /* these are the external protocols */
  640.     " ", " ", " ", " ", " ",
  641.     " ", " ", " ", " ", " ",
  642.     " ", " ", " ", " ", " ",
  643.     ""
  644.  
  645.     };
  646.   char  letter[2];
  647.   int   protocol;
  648.   label roomName;
  649.   if (roomBuf.rbflags.ISDIR != 1)
  650.     {
  651.     printf("\nSorry this is not a directory room.\nNew room? ");
  652.     ConOnly = TRUE;
  653.     getNormStr("", roomName, NAMESIZE, 0);
  654.     ConOnly = FALSE;
  655.     if (strLen(roomName) == 0) return;
  656.     gotoRoom(roomName, 'R');
  657.     if (roomBuf.rbflags.ISDIR != 1)
  658.       {
  659.       printf("\nNor is this is a directory room.\n");
  660.       return;
  661.  
  662.       }
  663.  
  664.     }
  665.   printf((Up) ? "Grabbing file from other system (into %s)\n" :
  666.   "Sending file to other system (from %s)\n", roomBuf.rbname);
  667.   ConOnly = TRUE;
  668.   AddExternProtocolOptions(Protocols, Up);
  669.   printf("\nProtocol: ");
  670.   CmdMenuList(Protocols, &CSelects, NULL, letter, FALSE, FALSE);
  671.   switch (letter[0])
  672.     {
  673.     #ifdef WXMODEM_AVAILABLE
  674.     case 'X':
  675.     case 'W':
  676.     case 'Y':
  677.     protocol    = (letter[0] == 'W') ? WXMDM :
  678.     (letter[0] == 'X') ? XMDM : YMDM;
  679.     break;
  680.     #else
  681.     case 'X':
  682.     case 'Y':
  683.     protocol    = (letter[0] == 'X') ? XMDM : YMDM;
  684.     break;
  685.     #endif
  686.     default:
  687.     if ((protocol = FindProtocolCode(letter[0], Up)) == -1)
  688.       {
  689.       ConOnly = FALSE;
  690.       /* KillList(&CSelects); */
  691.       return ;
  692.  
  693.       }
  694.  
  695.     }
  696.   if (Up) upLoad(protocol,NULL,FALSE);
  697.   else    TranFiles(protocol, "");
  698.   ConOnly = FALSE;
  699.   /* KillList(&CSelects); */
  700.   printf("\nBack in Chat.\n");
  701.  
  702.   }
  703. /*
  704. * interOut()
  705. *
  706. * This function actually implements chat capture and general interact()
  707. * output.
  708. */
  709. void interOut(char c)
  710.   {
  711.   mputChar(c);
  712.   if (captureOn)
  713.   fputc(c, cptFile);
  714.  
  715.   }
  716. /*
  717. * JumpStart()
  718. *
  719. * Generic jump start for Reception.
  720. */
  721. char JumpStart(int tries, int timeout, int Starter, int t1, int t2,
  722. char (*Method)(int (*wrt)(int c)), int (*WriteFn)(int c))
  723.   {
  724.   int StartTries;
  725.   for (StartTries = 0; StartTries < tries; StartTries++)
  726.     {
  727.     if (!gotCarrier())
  728.       {
  729.       #ifdef NEED_NET_DEBUG_ERRORS
  730.       if (inNet != NON_NET)
  731.       splitF(netLog, "RecError: JS Carr Loss\n");
  732.       #endif
  733.       return CARR_LOSS;
  734.  
  735.       }
  736.     outMod(Starter);
  737.     GlobalHeader = receive(timeout);
  738.     if (GlobalHeader == t1 || GlobalHeader == t2)
  739.       {
  740.       return (*Method)(WriteFn);
  741.  
  742.       }
  743.     if (GlobalHeader == CAN)
  744.       {
  745.       #ifdef NEED_NET_DEBUG_ERRORS
  746.       if (inNet != NON_NET)
  747.       splitF(netLog, "RecError: JS JS received CAN\n");
  748.       #endif
  749.       return CANCEL;
  750.  
  751.       }
  752.     if (GlobalHeader == EOT)
  753.       {
  754.       outMod(ACK);
  755.       return TRAN_SUCCESS;  /* zero length data */
  756.  
  757.       }
  758.  
  759.     }
  760.   return NO_LUCK;
  761.  
  762.   }
  763. /*
  764. * ModemSetup()
  765. *
  766. * This function will set up modem handling variables.
  767. */
  768. char ModemSetup(char ShouldBeCarrier)
  769.   {
  770.   haveCarrier = modStat = gotCarrier();
  771.   if (ShouldBeCarrier && !haveCarrier) return FALSE;
  772.   if (!ShouldBeCarrier && haveCarrier)
  773.     {
  774.     HangUp(TRUE);
  775.     haveCarrier = modStat = gotCarrier();
  776.  
  777.     }
  778.   return TRUE;
  779.  
  780.   }
  781. /**
  782. * modIn()
  783. *
  784. * toplevel modem-input function.
  785. *
  786. * If DCD status has changed since the last access, reports carrier present or
  787. * absent and sets flags as appropriate.  In case of a carrier loss, waits 20
  788. * ticks and rechecks carrier to make sure it was not a temporary glitch.
  789. * If carrier is newly received, returns newCarrier = TRUE;  if carrier lost
  790. * returns 0.  If carrier is present and state has not changed, gets a
  791. * character if present and returns it.  If a character is typed at the console,
  792. * checks to see if it is keyboard interrupt character.  If so, prints
  793. * short-form console menu and awaits next keyboard character.
  794. *
  795. * Globals modified:    carrierDetect   modStat    haveCarrier
  796. *     justLostCarrier whichIO   ExitToMsDos
  797. *     visibleMode
  798. * Returns:  modem or console input character,
  799. *   or above special values
  800. **/
  801. #define MAX_TIME  210l  /* Time out is 210 seconds  */
  802. AN_UNSIGNED modIn()
  803.   {
  804.   AN_UNSIGNED logVal = 0;
  805.   AN_UNSIGNED c;
  806.   char *whatRate;
  807.   char signal = FALSE;
  808.   if (PB)
  809.     {
  810.     c = PB;
  811.     PB = 0;
  812.     return c;
  813.  
  814.     }
  815.   if (!onLine() && CallSysop)SummonSysop();
  816.   startTimer(WORK_TIMER);
  817.   while (TRUE)
  818.     {
  819.     if ((whichIO==MODEM) && (c=gotCarrier()) != modStat)
  820.       {
  821.       /* carrier changed   */
  822.       if (c)
  823.         {
  824.         /* carrier present   */
  825.         if (Find_baud(&whatRate))
  826.           {
  827.           printf("Carr-detect (%s)\n", whatRate);
  828.           warned      = FALSE;
  829.           haveCarrier = TRUE;
  830.           modStat     = c;
  831.           newCarrier  = TRUE;
  832.           justLostCarrier = FALSE;
  833.           logMessage(BAUD, whatRate, FALSE);
  834.           ScrNewUser();
  835.  
  836.           }
  837.         else
  838.         HangUp(TRUE);
  839.         return(0);
  840.  
  841.         }
  842.       else
  843.         {
  844.         pause(100);   /* confirm it's not a glitch */
  845.         if (!gotCarrier())
  846.           {
  847.           /* check again */
  848.           printf("Carr-loss\n");
  849.           logMessage(CARRLOSS, "", logVal);
  850.           HangUp(TRUE);
  851.           modStat = haveCarrier = FALSE;
  852.           justLostCarrier = TRUE;
  853.           startTimer(NEXT_ANYNET);  /* start anytime net timer */
  854.           return(0);
  855.  
  856.           }
  857.  
  858.         }
  859.  
  860.       }
  861.     if (MIReady())
  862.       {
  863.       if (haveCarrier)
  864.         {
  865.         c = inp() & 0x7f;
  866.         if (whichIO == MODEM)   return c;
  867.  
  868.         }
  869.  
  870.       }
  871.     if (KBReady())
  872.       {
  873.       c = getCh();
  874.       if (whichIO == CONSOLE) return(c);
  875.       else
  876.         {
  877.         if (!SurreptitiousChar(c))
  878.         return 0;
  879.  
  880.         }
  881.  
  882.       }
  883.     if (DoTimeouts()) return 0;
  884.     /* check for no input.  (Short-circuit evaluation, remember!) */
  885.     if ((whichIO==MODEM  &&  haveCarrier  &&
  886.     chkTimeSince(WORK_TIMER) >= MAX_TIME) ||
  887.     (whichIO == CONSOLE && cfg.ConTimeOut != 0 &&
  888.     chkTimeSince(WORK_TIMER) >= cfg.ConTimeOut))
  889.       {
  890.       mPrintf("Sleeping? Call again :-)");
  891.       logVal = 't';
  892.       if (whichIO == MODEM)
  893.       HangUp(FALSE);
  894.       else
  895.         {
  896.         logMessage(CARRLOSS, "", logVal);
  897.         justLostCarrier = TRUE;
  898.         onConsole = FALSE;
  899.         return 0;
  900.  
  901.         }
  902.  
  903.       }
  904.     else if ((whichIO == MODEM &&
  905.     haveCarrier &&
  906.     chkTimeSince(WORK_TIMER) == MAX_TIME - 10) ||
  907.     (whichIO == CONSOLE && cfg.ConTimeOut != 0 &&
  908.     chkTimeSince(WORK_TIMER) == cfg.ConTimeOut - 10))
  909.       {
  910.       if (!signal)
  911.       oChar(BELL);
  912.       signal = TRUE;
  913.  
  914.       }
  915.     BeNice((haveCarrier || onConsole) ? INUSE_PAUSE : IDLE_PAUSE);
  916.  
  917.     }
  918.  
  919.   }
  920. /*
  921. * SurreptitiousChar()
  922. *
  923. * This function will process a console character when the system is in modem
  924. * mode.
  925. */
  926. int SurreptitiousChar(char c)
  927.   {
  928.   switch (toUpper(c))
  929.     {
  930.     case CON_NEXT:    /* ^T */
  931.     if (onLine())
  932.       {
  933.       CallSysop = !CallSysop;
  934.       printf("\nSysop call toggle is %s\n", CallSysop ? "ON" : "OFF");
  935.       ScrNewUser();
  936.       break;
  937.  
  938.       }
  939.     /* yes, don't break here! */
  940.     case SPECIAL:   /* ESC */
  941.     printf("CONSOLE mode\n ");
  942.     onConsole  = TRUE;
  943.     whichIO    = CONSOLE;
  944.     if (!gotCarrier())
  945.       {
  946.       DisableModem(FALSE);
  947.       logMessage(BAUD, "", FALSE);
  948.  
  949.       }
  950.     setUp(FALSE);
  951.     if (!gotCarrier())
  952.       {
  953.       ScrNewUser();
  954.       if (!NoConsoleBanner)
  955.       newCarrier = TRUE;
  956.  
  957.       }
  958.     warned = FALSE;
  959.     return FALSE;
  960.     case 1:     /* ^A */
  961.     ForceAnytime();
  962.     break;
  963.     case 5:     /* ^E */
  964.     anyEcho = !anyEcho;
  965.     ScrNewUser();
  966.     break;
  967.     case CNTRLD:
  968.     cfg.BoolFlags.debug  = !cfg.BoolFlags.debug;
  969.     break;
  970.     case CNTRLZ:
  971.     cfg.BoolFlags.noChat = !cfg.BoolFlags.noChat;
  972.     ScrNewUser();
  973.     break;
  974.  
  975.     }
  976.   return TRUE;
  977.  
  978.   }
  979. /*
  980. * oChar()
  981. *
  982. * This function is the top-level user-output routine.  It sends to modem port
  983. * and console, does conversion to upper-case etc as necessary in "debug" mode,
  984. * converts control chars to uppercase letters
  985. * Globals modified: prevChar
  986. */
  987. int delay_factor= -1;
  988. void oChar(char c)
  989.   {
  990.   prevChar = c;     /* for end-of-paragraph code    */
  991.   if (outFlag != OUTOK &&   /* s(kip) mode  */
  992.   outFlag != IMPERVIOUS)
  993.   return;
  994.   if( !onConsole && logBuf.lbdelay > 0 && delay_factor == -1)
  995.     {
  996.     delay_factor = ( 256 - logBuf.lbdelay );
  997.     };
  998.  
  999.   if (c == NEWLINE)   c = ' ';  /* doCR() handles real newlines */
  1000.   /* show on console  */
  1001.   if (outPut == DISK)
  1002.   putc(c, upfd);
  1003.   else
  1004.     {
  1005.     if (haveCarrier && !ConOnly)
  1006.     (*Table[TransProtocol].method)(c);
  1007.     if (TransProtocol == ASCII)
  1008.       {
  1009.       mputChar(c);
  1010.       if (!onConsole && logBuf.lbdelay > 0 )
  1011.          {
  1012.          if( delay_factor-- < 1 )
  1013.            {
  1014.            delay_factor = ( 256 - logBuf.lbdelay );
  1015.            MilliSecPause(3);
  1016.            };
  1017.          };
  1018.  
  1019.       }
  1020.  
  1021.     }
  1022.   crtColumn += (c == '\b') ? -1 : 1;
  1023.  
  1024.   }
  1025. /*
  1026. * PushBack()
  1027. */
  1028. void PushBack(char c)
  1029.   {
  1030.   PB = c;
  1031.  
  1032.   }
  1033. /*
  1034. * Reception()
  1035. *
  1036. * This function reads data, trying to use specified protocol.  Note: This only
  1037. * handles XMODEM, WXMODEM, and YMODEM.  Due to the multiple authors of these
  1038. * protocols, this code is a mess.  I do da best I can, wid da leetle brain
  1039. * giben me.
  1040. */
  1041. char Reception(int protocol, int (*WriteFn)(int c))
  1042.   {
  1043.   char RetVal;
  1044.   if (!gotCarrier())
  1045.   return CARR_LOSS;
  1046.   GenTrInit();
  1047.   #ifdef WXMODEM_AVAILABLE
  1048.   /* From P. Boswell's WXMODEM doc */
  1049.   if (protocol == WXMDM)
  1050.     {
  1051.     if ((RetVal = JumpStart(3, 3, 'W', SYN, SYN, recWX, WriteFn))
  1052.     != NO_LUCK)
  1053.     return RetVal;
  1054.     if ((RetVal = JumpStart(3, 3, 'C', SOH, SOH, recXYmodem, WriteFn))
  1055.     != NO_LUCK)
  1056.     return RetVal;
  1057.     DoCRC = FALSE;
  1058.     if ((RetVal = JumpStart(4, 3, NAK, SOH, SOH, recXYmodem, WriteFn))
  1059.     != NO_LUCK)
  1060.     return RetVal;
  1061.  
  1062.     }
  1063.   /* From Ward's XMODEM.DOC -- 10 seconds between start tries */
  1064.   else
  1065.   #endif
  1066.   if (protocol == XMDM)
  1067.     {
  1068.     if ((RetVal = JumpStart((inNet != NON_NET) ? 2 : 4, 10, 'C', SOH,
  1069.     SOH, recXYmodem, WriteFn)) != NO_LUCK)
  1070.     return RetVal;
  1071.     DoCRC = FALSE;
  1072.     if ((RetVal = JumpStart(6, 10, NAK, SOH, SOH, recXYmodem, WriteFn))
  1073.     != NO_LUCK)
  1074.     return RetVal;
  1075.  
  1076.     }
  1077.   /* Extrapolated from C. Forsberg's doc and WC's doc. */
  1078.   else if (protocol == YMDM)
  1079.   if ((RetVal = JumpStart(10, 10, 'C', SOH, STX, recXYmodem, WriteFn))
  1080.   != NO_LUCK)
  1081.   return RetVal;
  1082.   return NO_START;
  1083.  
  1084.   }
  1085. #ifdef WXMODEM_AVAILABLE
  1086. /*
  1087. * recWX()
  1088. *
  1089. * This function receives data via WXMODEM.
  1090. */
  1091. char recWX(int (*WriteFn)(int c))
  1092.   {
  1093.   int CurChar,
  1094.   LastChar, /* Confirm that SOH follows a SYN */
  1095.   lastReceived = 0,
  1096.   Sector,
  1097.   SectorResult,
  1098.   LastError = NO_ERROR,
  1099.   LastNak = -1;
  1100.   /*
  1101.   * Assume that the startup part of the protocol has completed, which would
  1102.   * be indicated by a SYN -- already received by us.
  1103.   */
  1104.   CurChar = SYN;
  1105.   do
  1106.     {
  1107.     DLinkError = NO_ERROR;
  1108.     if (inNet == NON_NET) printf("Awaiting block %d\r", lastReceived +1);
  1109.     /*
  1110.     * Get starting SOH, discarding leading SYN and other characters.
  1111.     */
  1112.     do
  1113.       {
  1114.       LastChar = CurChar;
  1115.       CurChar = recWXchar(15);
  1116.  
  1117.       }
  1118.     while (!(CurChar == SOH && LastChar == SYN) && CurChar != EOT &&
  1119.     gotCarrier());
  1120.     if (CurChar != EOT)
  1121.       {
  1122.       SectorResult = CommonPacket(WXMDM, 128, recWXchar, &Sector);
  1123.       if (SectorResult == NO_ERROR)
  1124.         {
  1125.         if (Sector == (lastReceived + 1) % 256)
  1126.           {
  1127.           SectorResult = CommonWrite(WriteFn, SECTSIZE);
  1128.           lastReceived = Sector;
  1129.  
  1130.           }
  1131.         sendWXchar(ACK);
  1132.         sendWXchar(Sector & 3);
  1133.  
  1134.         }
  1135.       if (SectorResult != NO_ERROR)
  1136.         {
  1137.         /*
  1138.         * See Section 6.4.4 of the WXMODEM doc.
  1139.         */
  1140.         /*      if (!inNet) printf("Error: %s\n", msg[SectorResult]); */
  1141.         #ifdef NEED_NET_DEBUG_ERRORS
  1142.         splitF(netLog, "Error: %s\n", msg[SectorResult]);
  1143.         #endif
  1144.         if (SectorResult == CARR_LOSS)
  1145.           {
  1146.           return TRAN_FAILURE;
  1147.  
  1148.           }
  1149.         if (SectorResult == WRITE_ERROR)
  1150.           {
  1151.           sendWXchar(CAN);    /* Cancel transfer - fatal error */
  1152.           sendWXchar(CAN);
  1153.           sendWXchar(CAN);
  1154.           return TRAN_FAILURE;
  1155.  
  1156.           }
  1157.         if (LastError == NO_ERROR || Sector == LastNak)
  1158.           {
  1159.           sendWXchar(NAK);
  1160.           sendWXchar(Sector & 3);
  1161.           LastError = SectorResult;
  1162.           LastNak = Sector;
  1163.  
  1164.           }
  1165.  
  1166.         }
  1167.       else if (lastReceived == Sector)
  1168.         {
  1169.         LastError = NO_ERROR;   /* Clear signal */
  1170.         LastNak   = -1;
  1171.  
  1172.         }
  1173.  
  1174.       }
  1175.  
  1176.     }
  1177.   while (CurChar != EOT);
  1178.   sendWXchar(ACK);    /* Ack the EOT, indicates end of file */
  1179.   return TRAN_SUCCESS;
  1180.  
  1181.   }
  1182. /*
  1183. * recWXchar()
  1184. *
  1185. * This function reads a character, strips any leading DLE.
  1186. */
  1187. int recWXchar(int ErrorTime)
  1188.   {
  1189.   int result;
  1190.   if ((result = receive(ErrorTime)) == ERROR)
  1191.   return ERROR;
  1192.   if (result == DLE)
  1193.     {
  1194.     DLEsignal = TRUE;
  1195.     if ((result = receive(ErrorTime)) == ERROR)
  1196.     return ERROR;
  1197.     result ^= 64;
  1198.     switch (result)
  1199.       {
  1200.       case DLE:
  1201.       case SYN:
  1202.       case XON:
  1203.       case XOFF: break;
  1204.       default:
  1205.       DLinkError = BAD_DLE;
  1206.       result  = ERROR;
  1207.       break;
  1208.  
  1209.       }
  1210.  
  1211.     }
  1212.   else DLEsignal = FALSE;
  1213.   return result;
  1214.  
  1215.   }
  1216. #endif
  1217. /*
  1218. * recXYmodem()
  1219. *
  1220. * This function receives data via YMODEM SINGLE.
  1221. *      (May also work with XMODEM...)
  1222. * Note: algorithm modified to ACK the transmitter before trying
  1223. * to write to disk (or wherever).  This should up performance, but
  1224. * at the expense code complexity.
  1225. */
  1226. char recXYmodem(int (*WriteFn)(int c))  /* Supports YMODEM SINGLE mode only */
  1227.   {
  1228.   char AbortTransmission = FALSE, WriteError = FALSE;
  1229.   int  SectorResult,    /* Result of packet read */
  1230.   Sector,   /* Sector # received */
  1231.   LastReceived = 0, /* Last sector received */
  1232.   TotalErrors = 0,  /* Total errors for this transmission */
  1233.   CurrentErrors = 0,  /* Total errors for block */
  1234.   SOH_val,    /* SOH indicates 128, STX 1024 */
  1235.   BufSize;    /* In conjunction with SOH_val */
  1236.   /*
  1237.   * Assume that the initial SOH or STX has been received.  An initial EOT
  1238.   * should also be handled by the startup function.
  1239.   */
  1240.   SOH_val = GlobalHeader; /* Set by startup function, is global */
  1241.   do
  1242.     {
  1243.     BufSize = (SOH_val == SOH) ? SECTSIZE : YM_BLOCK_SIZE;
  1244.     SectorResult = CommonPacket(YMDM, BufSize, receive, &Sector);
  1245.     if (WriteError) SectorResult = WRITE_ERROR;
  1246.     if (SectorResult == NO_ERROR)
  1247.       {
  1248.       if ((Sector == (LastReceived + 1) % 256) ||
  1249.       Sector == LastReceived)
  1250.       outMod(ACK);
  1251.       if (Sector == (LastReceived + 1) % 256)
  1252.         {
  1253.         WriteError = (CommonWrite(WriteFn, BufSize) == WRITE_ERROR);
  1254.         LastReceived++;
  1255.         if (inNet == NON_NET)
  1256.         printf("Block %d received (try %d, %d total errors)\r",
  1257.         LastReceived,
  1258.         CurrentErrors,
  1259.         TotalErrors);
  1260.  
  1261.         }
  1262.       else if (Sector != LastReceived)
  1263.       SectorResult = SYNCH_ERROR;
  1264.  
  1265.       }
  1266.     if (SectorResult != NO_ERROR)
  1267.       {
  1268.       TotalErrors++;
  1269.       splitF(netLog, "Error on sector %d: %s (%d)\n", LastReceived+1,msg[SectorResult],CurrentErrors+1);
  1270.       switch (SectorResult)
  1271.         {
  1272.         case SYNCH_ERROR:
  1273.         case WRITE_ERROR:
  1274.         outMod(CAN);
  1275.         outMod(CAN);
  1276.         outMod(CAN);    /* Fatal error -- cancel transmission */
  1277.         case CARR_LOSS: /* Don't bother with CANs here */
  1278.         AbortTransmission = TRUE;
  1279.         splitF(netLog, "\nAborting reception due to %s error\n",
  1280.         msg[SectorResult]);
  1281.         break;
  1282.         default:  /* Some normal problem */
  1283.         outMod(NAK);
  1284.         if (CurrentErrors++ >= 9)
  1285.           {
  1286.           AbortTransmission = TRUE;
  1287.           splitF(netLog,
  1288.           "Aborting reception due to 10 consecutive errors\n");
  1289.  
  1290.           }
  1291.  
  1292.         }
  1293.  
  1294.       }
  1295.     else
  1296.       {
  1297.       CurrentErrors = 0;
  1298.  
  1299.       }
  1300.     if (!AbortTransmission)
  1301.       {
  1302.       do
  1303.       SOH_val = receive(10);
  1304.       while (SOH_val != EOT && SOH_val != SOH && SOH_val != CAN &&
  1305.       SOH_val != STX && gotCarrier());
  1306.  
  1307.       }
  1308.  
  1309.     }
  1310.   while (SOH_val != EOT && !AbortTransmission && SOH_val != CAN);
  1311.   if (AbortTransmission)
  1312.   splitF(netLog, "Leaving recXY loop due to AT\n");
  1313.   if (!AbortTransmission && SOH_val != CAN )
  1314.     {
  1315.     outMod(ACK);    /* Ack the EOT, indicates end of file */
  1316.     return TRAN_SUCCESS;
  1317.  
  1318.     }
  1319.   else return TRAN_FAILURE;
  1320.  
  1321.   }
  1322. /*
  1323. * ringSysop()
  1324. *
  1325. * This function signals a chat mode request.  Exits on input from modem or
  1326. * keyboard.
  1327. */
  1328. #define RING_LIMIT 6
  1329. void ReActivate_Window(void);
  1330. void ringSysop()
  1331.   {
  1332.   char answered;
  1333.   int  i, ring;
  1334.   ReActivate_Window();
  1335.   mPrintf("\n Ringing sysop.\n ");
  1336.   answered = FALSE;
  1337.   for (ring = 0; ring < RING_LIMIT && !answered && gotCarrier(); ring++)
  1338.     {
  1339.     for (i=0; !BBSCharReady() && !KBReady(); i = ++i % 7)
  1340.       {
  1341.       /* play shave-and-a-haircut/two bits... as best we can: */
  1342.       oChar(BELL);
  1343.       pause(cfg.shave[i]);
  1344.       if (i == 6) ring++;
  1345.  
  1346.       }
  1347.     if (BBSCharReady() || KBReady()) answered = TRUE;
  1348.  
  1349.     }
  1350.   if (KBReady())
  1351.     {
  1352.     getCh();
  1353.     whichIO = CONSOLE;
  1354.     interact(TRUE);
  1355.     whichIO = MODEM;
  1356.  
  1357.     }
  1358.   else if (ring >= RING_LIMIT)
  1359.     {
  1360.     cfg.BoolFlags.noChat = TRUE;
  1361.     mPrintf("\n Sorry, Sysop not around...\n ");
  1362.  
  1363.     }
  1364.   else modIn();
  1365.  
  1366.   }
  1367. /*
  1368. * SendCmnBlk()
  1369. *
  1370. * This function sends a WX/X/Y Modem block.
  1371. */
  1372. void SendCmnBlk(char type, TransferBlock *block,char (*SendFn)(int c), int size)
  1373.   {
  1374.   int rover;
  1375.   #ifndef NEED_NET_DEBUG_ERRORS
  1376.   if (inNet == NON_NET)
  1377.   printf("Sending block %d\r", block->ThisBlock);
  1378.   #else
  1379.   splitF(netLog, "Sending block %d, type %d, size %d\n", block->ThisBlock, type, size);
  1380.   #endif
  1381.   #ifdef WXMODEM_AVAILABLE
  1382.   if (type == WXMDM)
  1383.     {
  1384.     /* Thrust out some SYNs first */
  1385.     fastMod(SYN);
  1386.     fastMod(SYN);
  1387.  
  1388.     }
  1389.   else
  1390.   #endif
  1391.   BufferingOn();
  1392.   (*SendFn)((size == SECTSIZE) ? SOH : STX);
  1393.   (*SendFn)(block->ThisBlock & 0xFF);
  1394.   (*SendFn)(~(block->ThisBlock & 0xff));
  1395.   for (rover = 0; rover < size; rover++)
  1396.     {
  1397.     (*SendFn)(block->buf[rover]);
  1398.     #ifdef WXMODEM_AVAILABLE
  1399.     if (type == WXMDM) WXResponses();
  1400.     #endif
  1401.     if (!gotCarrier())
  1402.       {
  1403.       TrError = CARR_LOSS;
  1404.       splitF(netLog, "SendCmnBlk lost carrier\n");
  1405.       BufferingOff();
  1406.       return ;
  1407.  
  1408.       }
  1409.  
  1410.     }
  1411.   /*
  1412.   * Handle CRC/Checksum stuff.
  1413.   */
  1414.   if (DoCRC)
  1415.     {
  1416.     (*SendFn)(((block->ThisCRC & 0xff00) >> 8));
  1417.  
  1418.     }
  1419.   (*SendFn)(block->ThisCRC & 0xff);
  1420.   BufferingOff();
  1421.  
  1422.   }
  1423. /*
  1424. * sendWCChar()
  1425. *
  1426. * This function sends a file using Ward Christensen's protocol.
  1427. * (i.e., compatable with xModem, modem7, modem2, YAM, ... )
  1428. */
  1429. int sendWCChar(int c)
  1430.   {
  1431.   if (TrError != TRAN_SUCCESS)
  1432.   return FALSE;
  1433.   blk.buf[TrCount++] = c;
  1434.   TrCksm = (TrCksm + c) & 0xFF;
  1435.   if (TrCount != SECTSIZE)
  1436.   return TRUE;
  1437.   blk.ThisBlock = TrBlock;
  1438.   blk.ThisCRC   = (DoCRC) ? calcrc(blk.buf, SECTSIZE) : TrCksm;
  1439.   return (XYBlock(XMDM, SECTSIZE));
  1440.  
  1441.   }
  1442. #ifdef WXMODEM_AVAILABLE
  1443. /*
  1444. * sendWXchar()
  1445. *
  1446. * This function sends a char via WXMODEM with appropriate leaders, etc.
  1447. */
  1448. char sendWXchar(int data)
  1449.   {
  1450.   data &= 0xff;
  1451.   switch (data)
  1452.     {
  1453.     case DLE:
  1454.     case SYN:
  1455.     case XON:
  1456.     case XOFF:
  1457.     fastMod(DLE);
  1458.     fastMod(data ^ 64);
  1459.     break;
  1460.     default:
  1461.     fastMod(data);
  1462.     break;
  1463.  
  1464.     }
  1465.   return 0;
  1466.  
  1467.   }
  1468. /*
  1469. * sendWXModem()
  1470. *
  1471. * This function sends a character using WXMODEM protocol.
  1472. */
  1473. int sendWXModem(int c)
  1474.   {
  1475.   int BlockRover, TempSent, LoopCount;
  1476.   /*
  1477.   * First, check for terminal failure.
  1478.   */
  1479.   if (TrError != TRAN_SUCCESS) return FALSE;
  1480.   /*
  1481.   * Process current character.
  1482.   */
  1483.   Twindow[CurWindow].buf[TrCount] = c;
  1484.   /*
  1485.   * Block is full, so clean up details in preparation for transmission.
  1486.   */
  1487.   if (++TrCount == SECTSIZE)
  1488.     {
  1489.     Twindow[CurWindow].ThisBlock = TrBlock;
  1490.     Twindow[CurWindow].ThisCRC = calcrc(Twindow[CurWindow].buf, SECTSIZE);
  1491.     Twindow[CurWindow].status = SECTOR_READY;   /* Set to go */
  1492.     /* TrBlock = (TrBlock + 1) % 256; line below should work -- see SendCmnBlk */
  1493.     TrBlock++;
  1494.     CurWindow = (CurWindow + 1) % 4;
  1495.     TrCount = 0;
  1496.  
  1497.     }
  1498.   /*
  1499.   * Check for responses from receiver.
  1500.   */
  1501.   WXResponses();
  1502.   /*
  1503.   * Now we need to send outstanding blocks.
  1504.   */
  1505.   for (    BlockRover = (LastSent + 1) % 4, TempSent = LastSent;
  1506.   BlockRover != LastSent; BlockRover = (BlockRover + 1) % 4)
  1507.     {
  1508.     if (Twindow[BlockRover].status != SECTOR_READY) break;
  1509.     SendCmnBlk(WXMDM, Twindow + BlockRover, sendWXchar, SECTSIZE);
  1510.     Twindow[BlockRover].status = SENT;
  1511.     TempSent = BlockRover;
  1512.     if (!gotCarrier())
  1513.       {
  1514.       break;
  1515.  
  1516.       }
  1517.  
  1518.     }
  1519.   LastSent = TempSent;
  1520.   /*
  1521.   * Now we need to check to see if the Twindow is "full"
  1522.   */
  1523.   for (LoopCount = 0; gotCarrier() && WindowFull() &&
  1524.   LoopCount < MAX_WX_ERRORS;
  1525.   LoopCount++)
  1526.     {
  1527.     startTimer(WORK_TIMER);
  1528.     do
  1529.     WXResponses();
  1530.     while (chkTimeSince(WORK_TIMER) < 10 && WindowFull());
  1531.     if (WindowFull())
  1532.     SendCmnBlk(WXMDM, Twindow + LastSent, sendWXchar, SECTSIZE);
  1533.  
  1534.     }
  1535.   /*
  1536.   * If the Twindow is still full at this point, then we've suffered some
  1537.   * sort of fatal error, and it's time to bomb out.
  1538.   */
  1539.   if (WindowFull() || !gotCarrier())
  1540.     {
  1541.     TrError = TRAN_FAILURE;
  1542.     return FALSE;
  1543.  
  1544.     }
  1545.   return TRUE;
  1546.  
  1547.   }
  1548. #endif
  1549. /*
  1550. * sendYMChar()
  1551. *
  1552. * This function sends a character using YMODEM protocol.
  1553. */
  1554. int sendYMChar(int c)
  1555.   {
  1556.   if (TrError != TRAN_SUCCESS)
  1557.   return FALSE;
  1558.   blk.buf[TrCount++] = c;
  1559.   if (TrCount != CurYBufSize)
  1560.   return TRUE;
  1561.   return SendYBlk();
  1562.  
  1563.   }
  1564. /*
  1565. * SendYBlk()
  1566. *
  1567. * This function sends a YMODEM block.
  1568. */
  1569. int SendYBlk()
  1570.   {
  1571.   blk.ThisBlock = TrBlock;
  1572.   blk.ThisCRC   = calcrc(blk.buf, CurYBufSize);
  1573.   return XYBlock(YMDM, CurYBufSize);
  1574.  
  1575.   }
  1576. /*
  1577. * SummonSysop()
  1578. *
  1579. * This function rings the sysop for ^T.
  1580. */
  1581. void SummonSysop()
  1582.   {
  1583.   int i;
  1584.   CallSysop = FALSE;
  1585.   DisableModem(FALSE);
  1586.   ReActivate_Window();  /* allow window to be activated and to the front */
  1587.   printf("SYSOP: System available!  Hit space!\n");
  1588.   for (i = 0; i < 12 && !KBReady(); i++)
  1589.     {
  1590.     onConsole = TRUE;
  1591.     printf("%c", BELL);
  1592.     onConsole = FALSE;
  1593.     startTimer(WORK_TIMER);
  1594.     while (!KBReady() && chkTimeSince(WORK_TIMER) < 10l)
  1595.     ;
  1596.  
  1597.     }
  1598.   if (KBReady())
  1599.     {
  1600.     getCh();
  1601.     printf("CONSOLE mode\n ");
  1602.     whichIO = CONSOLE;
  1603.     setUp(FALSE);
  1604.     ScrNewUser();
  1605.     warned  = FALSE;
  1606.     logMessage(BAUD, "", FALSE);
  1607.  
  1608.     }
  1609.   else
  1610.     {
  1611.     printf("No answer.  System back on MODEM.\n");
  1612.     EnableModem(FALSE);
  1613.  
  1614.     }
  1615.   givePrompt();
  1616.  
  1617.   }
  1618. /*
  1619. * Transmission()
  1620. *
  1621. * Starts protocols up.
  1622. * Note: This only handles XMODEM, WXMODEM, and YMODEM.
  1623. */
  1624. char Transmission(int protocol, char mode)  /* Transmission handler */
  1625.   {
  1626.   int Errors, m;
  1627.   if (!gotCarrier() && protocol != ASCII)
  1628.     {
  1629.     #ifdef NEED_NET_DEBUG_ERRORS
  1630.     if (inNet != NON_NET)
  1631.     splitF(netLog, "Error: Transmission() got carrier loss\n");
  1632.     #endif
  1633.     return CARR_LOSS;
  1634.  
  1635.     }
  1636.   if (protocol == ASCII) return TRAN_SUCCESS;
  1637.   if (mode == STARTUP)
  1638.     {
  1639.     GenTrInit();
  1640.     ByteCount = 0l;
  1641.     for (Errors = 0; Errors < ERRORMAX; Errors++)
  1642.       {
  1643.       m = receive(MINUTE);
  1644.       switch (m)
  1645.         {
  1646.         case CAN:
  1647.         if (cfg.BoolFlags.debug) splitF(netLog, "Transmission() CANned\n");
  1648.         return CANCEL;
  1649.         case ERROR:
  1650.         if (cfg.BoolFlags.debug) splitF(netLog, "Transmission() did not start\n");
  1651.         return NO_START;
  1652.         case NAK:
  1653.         TransProtocol = XMDM;
  1654.         DoCRC = FALSE;
  1655.         return TRAN_SUCCESS;
  1656.         #ifdef WXMODEM_AVAILABLE
  1657.         case 'W':
  1658.         if (protocol == WXMDM)
  1659.           {
  1660.           TransProtocol = WXMDM;
  1661.           return TRAN_SUCCESS;
  1662.  
  1663.           }
  1664.         break;
  1665.         #endif
  1666.         case 'C':
  1667.         if (protocol == YMDM)
  1668.           {
  1669.           /* Kludge for floopy performance */
  1670.           CurYBufSize = 1024;
  1671.           TransProtocol = YMDM;
  1672.           return TRAN_SUCCESS;
  1673.  
  1674.           }
  1675.         TransProtocol = XMDM;
  1676.         return TRAN_SUCCESS;
  1677.         default:
  1678.         if (cfg.BoolFlags.debug) splitF(netLog, "TrStart: -%c (0x%x)-\n", m, m);
  1679.  
  1680.         }
  1681.  
  1682.       }
  1683.     if (cfg.BoolFlags.debug) splitF(netLog, "returning NO_START on loop exit.\n");
  1684.     return NO_START;    /* If we make it out of the loop, error */
  1685.  
  1686.     }
  1687.   else
  1688.     {
  1689.     if (inNet == NON_NET) printf("\n");
  1690.     if (TrError != TRAN_SUCCESS)
  1691.       {
  1692.       splitF(netLog, "TranFin found TrError was bad immediately\n");
  1693.       return TrError;
  1694.  
  1695.       }
  1696.     if (TransProtocol == YMDM && TrCount < SECTSIZE)
  1697.     CurYBufSize = SECTSIZE;
  1698.     while (TrCount != 0)
  1699.       {
  1700.       (*Table[TransProtocol].method)(' ');
  1701.  
  1702.       }
  1703.     if (TrError != TRAN_SUCCESS)
  1704.       {
  1705.       splitF(netLog, "TranFin found TrError after buffer fill\n");
  1706.       return TrError;
  1707.  
  1708.       }
  1709.     if (Table[TransProtocol].CleanUp != NULL)
  1710.       {
  1711.       return (char) (*Table[TransProtocol].CleanUp)();
  1712.  
  1713.       }
  1714.     TransProtocol = ASCII;  /* Return to normal */
  1715.     return TRAN_SUCCESS;
  1716.  
  1717.     }
  1718.   }
  1719. #ifdef WXMODEM_AVAILABLE
  1720. /*
  1721. * WXResponses()
  1722. *
  1723. * Handles ACK/NAK and XON/XOFF for WXMODEM.
  1724. */
  1725. void WXResponses()
  1726.   {
  1727.   int rover, sig, old, SeqReceived;
  1728.   if (MIReady())
  1729.     {
  1730.     sig = recWXchar(1);
  1731.     switch (sig)
  1732.       {
  1733.       case XOFF:
  1734.       FlowControl();
  1735.       break;
  1736.       case ACK:
  1737.       case NAK:
  1738.       SeqReceived = recWXchar(5) & 0x03;
  1739.       if (sig == ACK)
  1740.         {
  1741.         rover = StartWindow;
  1742.         do
  1743.           {
  1744.           Twindow[rover].status = ACKED;
  1745.           old = rover;
  1746.           rover = (rover + 1) % 4;
  1747.  
  1748.           }
  1749.         while (old != SeqReceived);
  1750.         StartWindow = rover;    /* First block of Twindow */
  1751.  
  1752.         }
  1753.       else
  1754.         {
  1755.         /* NAK */
  1756.         LastSent = (SeqReceived == 0) ? 3 : (SeqReceived - 1);
  1757.         rover = SeqReceived;
  1758.         do
  1759.           {
  1760.           Twindow[rover].status = SECTOR_READY;
  1761.           rover = (rover + 1) % 4;
  1762.  
  1763.           }
  1764.         while (rover != CurWindow);
  1765.  
  1766.         }
  1767.       break;
  1768.  
  1769.       }
  1770.  
  1771.     }
  1772.  
  1773.   }
  1774. #endif
  1775. /*
  1776. * XYBlock()
  1777. *
  1778. * This function handles common work of XMODEM and YMODEM.
  1779. */
  1780. char XYBlock(int mode, int size)
  1781.   {
  1782.   int i, m = CAN;
  1783.   #ifdef NEED_NET_DEBUG
  1784.   splitF(netLog, "In XYBlock\n");
  1785.   #endif
  1786.   ByteCount += size;
  1787.   for (i = 0; i < ERRORMAX; i++)
  1788.     {
  1789.     SendCmnBlk(mode, &blk, outMod, size);
  1790.     while (MIReady()) inp();  /* clear line */
  1791.     m = receive(10);  /* wait 10 seconds for return ACK/NAK */
  1792.     if (m == ACK || m == CAN || !gotCarrier()) break;
  1793.     #ifdef NEED_NET_DEBUG_ERRORS
  1794.     if (inNet != NON_NET)
  1795.     splitF(netLog, "Tr Resend (m=%c [%x])\n", m, m);
  1796.     #endif
  1797.  
  1798.     }
  1799.   TrCksm  = TrCount = 0;
  1800.   TrBlock++;
  1801.   if (m == ACK)
  1802.     {
  1803.     #ifdef NEED_NET_DEBUG_ERRORS
  1804.     if (inNet != NON_NET)
  1805.     splitF(netLog, "Ack on block\n");
  1806.     #endif
  1807.     return TRUE;
  1808.  
  1809.     }
  1810.   TrError = TRAN_FAILURE;
  1811.   if (inNet == NON_NET) printf("Aborting\n ");
  1812.   else splitF(netLog, "XYBlock aborting (%s)\n", (gotCarrier()) ? "10 NAKs" :
  1813.   "carrier loss");
  1814.   return FALSE;
  1815.  
  1816.   }
  1817. /*
  1818. * XYClear()
  1819. *
  1820. * This function finishes XMODEM and YMODEM transmission.
  1821. */
  1822. int XYClear()
  1823.   {
  1824.   int i, m;
  1825.   for (i = 0; gotCarrier() && i < ERRORMAX; i++)
  1826.     {
  1827.     #ifdef NEED_NET_DEBUG
  1828.     splitF(netLog, "Sending EOT\n");
  1829.     #endif
  1830.     outMod(EOT);
  1831.     if ((m = receive(10)) == ACK)
  1832.     return TRAN_SUCCESS;
  1833.     if (m == CAN)
  1834.     return TRAN_FAILURE;
  1835.  
  1836.     }
  1837.   return TRAN_FAILURE;
  1838.  
  1839.   }
  1840. /*
  1841. * YMHdr()
  1842. *
  1843. * This function sends the header for a YMODEM BATCH transmission.
  1844. */
  1845. int YMHdr(long fileSize, char *filename)
  1846.   {
  1847.   extern int (*ITLFunc)(int c);
  1848.   TrBlock    = 0; /* One a kludge, two a kludge, three a kludge .. */
  1849.   ITLFunc = sendYMChar;
  1850.   mTrPrintf("%s", filename);
  1851.   mTrPrintf("%ld", fileSize);
  1852.   if (TrCount < 128)
  1853.   CurYBufSize = 128;
  1854.   if (TrCount != 128)
  1855.   for (; TrCount != 0 && sendYMChar(0); )
  1856.   ;
  1857.   else
  1858.   SendYBlk();
  1859.   if (TrError != TRAN_SUCCESS) return FALSE;
  1860.   if (strLen(filename) != 0)
  1861.   Transmission(YMDM, STARTUP);  /* now restart protocol *sigh* */
  1862.   return TrError == TRAN_SUCCESS;
  1863.  
  1864.   }
  1865. #ifdef NEED_NET_DEBUG_ERRORS
  1866. void DumpToFile(int LastReceived, int BufSize, CRC_TYPE tc, CRC_TYPE oc)
  1867.   {
  1868.   int i, j;
  1869.   FILE *fd;
  1870.   extern NetBuffer netBuf;
  1871.   if (strCmpU(netBuf.netName, "Images") == 0)
  1872.     {
  1873.     if ((fd = fopen("badsector", "a")) != NULL)
  1874.       {
  1875.       fprintf(fd, "Error on sector %d.  Their crc is %x, our's %x. Contents:\n", LastReceived, tc, oc);
  1876.       for (i = 0; i < BufSize; i += 16)
  1877.         {
  1878.         fprintf(fd, "%2x:", i);
  1879.         for (j = i; j < i + 16; j++)
  1880.         fprintf(fd, " %02x", DataBuf[j]);
  1881.         fprintf(fd, "   ");
  1882.         for (j = i; j < i + 16; j++)
  1883.         fprintf(fd, "%c", isprint(DataBuf[j]) ? DataBuf[j] : '.');
  1884.         fprintf(fd, "\n");
  1885.  
  1886.         }
  1887.       fprintf(fd, "\n");
  1888.       fclose(fd);
  1889.  
  1890.       }
  1891.  
  1892.     }
  1893.  
  1894.   }
  1895. #endif
  1896.